home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / win / tkWinX.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  24.7 KB  |  1,045 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkWinX.c --
  3.  *
  4.  *    This file contains Windows emulation procedures for X routines. 
  5.  *
  6.  * Copyright (c) 1995-1996 Sun Microsystems, Inc.
  7.  * Copyright (c) 1994 Software Research Associates, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkWinX.c 1.50 97/08/06 15:36:47
  13.  */
  14.  
  15. #include "tkInt.h"
  16. #include "tkWinInt.h"
  17.  
  18. /*
  19.  * Definitions of extern variables supplied by this file.
  20.  */
  21.  
  22. int tkpIsWin32s = -1;
  23.  
  24. /*
  25.  * Declarations of static variables used in this file.
  26.  */
  27.  
  28. static HINSTANCE tkInstance = (HINSTANCE) NULL;
  29.                 /* Global application instance handle. */
  30. static TkDisplay *winDisplay;    /* Display that represents Windows screen. */
  31. static char winScreenName[] = ":0";
  32.                 /* Default name of windows display. */
  33. static WNDCLASS childClass;    /* Window class for child windows. */
  34. static childClassInitialized = 0; /* Registered child class? */
  35.  
  36. /*
  37.  * Forward declarations of procedures used in this file.
  38.  */
  39.  
  40. static void        GenerateXEvent _ANSI_ARGS_((HWND hwnd, UINT message,
  41.                 WPARAM wParam, LPARAM lParam));
  42. static unsigned int    GetState _ANSI_ARGS_((UINT message, WPARAM wParam,
  43.                 LPARAM lParam));
  44. static void         GetTranslatedKey _ANSI_ARGS_((XKeyEvent *xkey));
  45.  
  46. /*
  47.  *----------------------------------------------------------------------
  48.  *
  49.  * TkGetServerInfo --
  50.  *
  51.  *    Given a window, this procedure returns information about
  52.  *    the window server for that window.  This procedure provides
  53.  *    the guts of the "winfo server" command.
  54.  *
  55.  * Results:
  56.  *    None.
  57.  *
  58.  * Side effects:
  59.  *    None.
  60.  *
  61.  *----------------------------------------------------------------------
  62.  */
  63.  
  64. void
  65. TkGetServerInfo(interp, tkwin)
  66.     Tcl_Interp *interp;        /* The server information is returned in
  67.                  * this interpreter's result. */
  68.     Tk_Window tkwin;        /* Token for window;  this selects a
  69.                  * particular display and server. */
  70. {
  71.     char buffer[50];
  72.     OSVERSIONINFO info;
  73.  
  74.     info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  75.     GetVersionEx(&info);
  76.     sprintf(buffer, "Windows %d.%d %d ", info.dwMajorVersion,
  77.         info.dwMinorVersion, info.dwBuildNumber);
  78.     Tcl_AppendResult(interp, buffer,
  79.         (info.dwPlatformId == VER_PLATFORM_WIN32s) ? "Win32s" : "Win32",
  80.         (char *) NULL);
  81. }
  82.  
  83. /*
  84.  *----------------------------------------------------------------------
  85.  *
  86.  * TkWinGetTkModule --
  87.  *
  88.  *    This function returns the module handle for the Tk DLL.
  89.  *
  90.  * Results:
  91.  *    Returns the library module handle.
  92.  *
  93.  * Side effects:
  94.  *    None.
  95.  *
  96.  *----------------------------------------------------------------------
  97.  */
  98.  
  99. HMODULE
  100. TkWinGetTkModule()
  101. {
  102.     char libName[13];
  103.     sprintf(libName, "tk%d%d.dll", TK_MAJOR_VERSION, TK_MINOR_VERSION);
  104.     return GetModuleHandle(libName);
  105. }
  106.  
  107. /*
  108.  *----------------------------------------------------------------------
  109.  *
  110.  * Tk_GetHINSTANCE --
  111.  *
  112.  *    Retrieves the global instance handle used by the Tk library.
  113.  *
  114.  * Results:
  115.  *    Returns the global instance handle.
  116.  *
  117.  * Side effects:
  118.  *    None.
  119.  *
  120.  *----------------------------------------------------------------------
  121.  */
  122.  
  123. HINSTANCE
  124. Tk_GetHINSTANCE()
  125. {
  126.     return tkInstance;
  127. }
  128.  
  129. /*
  130.  *----------------------------------------------------------------------
  131.  *
  132.  * TkWinXInit --
  133.  *
  134.  *    Initialize Xlib emulation layer.
  135.  *
  136.  * Results:
  137.  *    None.
  138.  *
  139.  * Side effects:
  140.  *    Sets up various data structures.
  141.  *
  142.  *----------------------------------------------------------------------
  143.  */
  144.  
  145. void
  146. TkWinXInit(hInstance)
  147.     HINSTANCE hInstance;
  148. {
  149.     OSVERSIONINFO info;
  150.  
  151.     info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  152.     GetVersionEx(&info);
  153.     tkpIsWin32s = (info.dwPlatformId == VER_PLATFORM_WIN32s);
  154.  
  155.     if (childClassInitialized != 0) {
  156.     return;
  157.     }
  158.     childClassInitialized = 1;
  159.  
  160.     tkInstance = hInstance;
  161.  
  162.     childClass.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC;
  163.     childClass.cbClsExtra = 0;
  164.     childClass.cbWndExtra = 0;
  165.     childClass.hInstance = hInstance;
  166.     childClass.hbrBackground = NULL;
  167.     childClass.lpszMenuName = NULL;
  168.  
  169.     /*
  170.      * Register the Child window class.
  171.      */
  172.  
  173.     childClass.lpszClassName = TK_WIN_CHILD_CLASS_NAME;
  174.     childClass.lpfnWndProc = TkWinChildProc;
  175.     childClass.hIcon = NULL;
  176.     childClass.hCursor = NULL;
  177.  
  178.     if (!RegisterClass(&childClass)) {
  179.     panic("Unable to register TkChild class");
  180.     }
  181. }
  182.  
  183. /*
  184.  *----------------------------------------------------------------------
  185.  *
  186.  * TkWinXCleanup --
  187.  *
  188.  *    Removes the registered classes for Tk.
  189.  *
  190.  * Results:
  191.  *    None.
  192.  *
  193.  * Side effects:
  194.  *    Removes window classes from the system.
  195.  *
  196.  *----------------------------------------------------------------------
  197.  */
  198.  
  199. void
  200. TkWinXCleanup(hInstance)
  201.     HINSTANCE hInstance;
  202. {
  203.     /*
  204.      * Clean up our own class.
  205.      */
  206.     
  207.     if (childClassInitialized) {
  208.         childClassInitialized = 0;
  209.         UnregisterClass(TK_WIN_CHILD_CLASS_NAME, hInstance);
  210.     }
  211.  
  212.     /*
  213.      * And let the window manager clean up its own class(es).
  214.      */
  215.     
  216.     TkWinWmCleanup(hInstance);
  217. }
  218.  
  219. /*
  220.  *----------------------------------------------------------------------
  221.  *
  222.  * TkGetDefaultScreenName --
  223.  *
  224.  *    Returns the name of the screen that Tk should use during
  225.  *    initialization.
  226.  *
  227.  * Results:
  228.  *    Returns a statically allocated string.
  229.  *
  230.  * Side effects:
  231.  *    None.
  232.  *
  233.  *----------------------------------------------------------------------
  234.  */
  235.  
  236. char *
  237. TkGetDefaultScreenName(interp, screenName)
  238.     Tcl_Interp *interp;        /* Not used. */
  239.     char *screenName;        /* If NULL, use default string. */
  240. {
  241.     if ((screenName == NULL) || (screenName[0] == '\0')) {
  242.     screenName = winScreenName;
  243.     }
  244.     return screenName;
  245. }
  246.  
  247. /*
  248.  *----------------------------------------------------------------------
  249.  *
  250.  * TkpOpenDisplay --
  251.  *
  252.  *    Create the Display structure and fill it with device
  253.  *    specific information.
  254.  *
  255.  * Results:
  256.  *    Returns a Display structure on success or NULL on failure.
  257.  *
  258.  * Side effects:
  259.  *    Allocates a new Display structure.
  260.  *
  261.  *----------------------------------------------------------------------
  262.  */
  263.  
  264. TkDisplay *
  265. TkpOpenDisplay(display_name)
  266.     char *display_name;
  267. {
  268.     Screen *screen;
  269.     HDC dc;
  270.     TkWinDrawable *twdPtr;
  271.     Display *display;
  272.  
  273.     if (winDisplay != NULL) {
  274.     if (strcmp(winDisplay->display->display_name, display_name) == 0) {
  275.         return winDisplay;
  276.     } else {
  277.         return NULL;
  278.     }
  279.     }
  280.  
  281.     display = (Display *) ckalloc(sizeof(Display));
  282.     display->display_name = (char *) ckalloc(strlen(display_name)+1);
  283.     strcpy(display->display_name, display_name);
  284.  
  285.     display->cursor_font = 1;
  286.     display->nscreens = 1;
  287.     display->request = 1;
  288.     display->qlen = 0;
  289.  
  290.     screen = (Screen *) ckalloc(sizeof(Screen));
  291.     screen->display = display;
  292.  
  293.     dc = GetDC(NULL);
  294.     screen->width = GetDeviceCaps(dc, HORZRES);
  295.     screen->height = GetDeviceCaps(dc, VERTRES);
  296.     screen->mwidth = MulDiv(screen->width, 254,
  297.         GetDeviceCaps(dc, LOGPIXELSX) * 10);
  298.     screen->mheight = MulDiv(screen->height, 254,
  299.         GetDeviceCaps(dc, LOGPIXELSY) * 10);
  300.     
  301.     /*
  302.      * Set up the root window.
  303.      */
  304.  
  305.     twdPtr = (TkWinDrawable*) ckalloc(sizeof(TkWinDrawable));
  306.     if (twdPtr == NULL) {
  307.     return None;
  308.     }
  309.     twdPtr->type = TWD_WINDOW;
  310.     twdPtr->window.winPtr = NULL;
  311.     twdPtr->window.handle = NULL;
  312.     screen->root = (Window)twdPtr;
  313.  
  314.     /*
  315.      * On windows, when creating a color bitmap, need two pieces of 
  316.      * information: the number of color planes and the number of 
  317.      * pixels per plane.  Need to remember both quantities so that
  318.      * when constructing an HBITMAP for offscreen rendering, we can
  319.      * specify the correct value for the number of planes.  Otherwise
  320.      * the HBITMAP won't be compatible with the HWND and we'll just
  321.      * get blank spots copied onto the screen.
  322.      */
  323.  
  324.     screen->ext_data = (XExtData *) GetDeviceCaps(dc, PLANES);
  325.     screen->root_depth = GetDeviceCaps(dc, BITSPIXEL) * (int) screen->ext_data;
  326.  
  327.     screen->root_visual = (Visual *) ckalloc(sizeof(Visual));
  328.     screen->root_visual->visualid = 0;
  329.     if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
  330.     screen->root_visual->map_entries = GetDeviceCaps(dc, SIZEPALETTE);
  331.     screen->root_visual->class = PseudoColor;
  332.     screen->root_visual->red_mask = 0x0;
  333.     screen->root_visual->green_mask = 0x0;
  334.     screen->root_visual->blue_mask = 0x0;
  335.     } else {
  336.     if (screen->root_depth == 4) {
  337.         screen->root_visual->class = StaticColor;
  338.         screen->root_visual->map_entries = 16;
  339.     } else if (screen->root_depth == 8) {
  340.         screen->root_visual->class = StaticColor;
  341.         screen->root_visual->map_entries = 256;
  342.     } else if (screen->root_depth == 12) {
  343.         screen->root_visual->class = TrueColor;
  344.         screen->root_visual->map_entries = 32;
  345.         screen->root_visual->red_mask = 0xf0;
  346.         screen->root_visual->green_mask = 0xf000;
  347.         screen->root_visual->blue_mask = 0xf00000;
  348.     } else if (screen->root_depth == 16) {
  349.         screen->root_visual->class = TrueColor;
  350.         screen->root_visual->map_entries = 64;
  351.         screen->root_visual->red_mask = 0xf8;
  352.         screen->root_visual->green_mask = 0xfc00;
  353.         screen->root_visual->blue_mask = 0xf80000;
  354.     } else if (screen->root_depth >= 24) {
  355.         screen->root_visual->class = TrueColor;
  356.         screen->root_visual->map_entries = 256;
  357.         screen->root_visual->red_mask = 0xff;
  358.         screen->root_visual->green_mask = 0xff00;
  359.         screen->root_visual->blue_mask = 0xff0000;
  360.     }
  361.     }
  362.     screen->root_visual->bits_per_rgb = screen->root_depth;
  363.     ReleaseDC(NULL, dc);
  364.  
  365.     /*
  366.      * Note that these pixel values are not palette relative.
  367.      */
  368.  
  369.     screen->white_pixel = RGB(255, 255, 255);
  370.     screen->black_pixel = RGB(0, 0, 0);
  371.  
  372.     display->screens = screen;
  373.     display->nscreens = 1;
  374.     display->default_screen = 0;
  375.     screen->cmap = XCreateColormap(display, None, screen->root_visual,
  376.         AllocNone);
  377.     winDisplay = (TkDisplay *) ckalloc(sizeof(TkDisplay));
  378.     winDisplay->display = display;
  379.     return winDisplay;
  380. }
  381.  
  382. /*
  383.  *----------------------------------------------------------------------
  384.  *
  385.  * TkpCloseDisplay --
  386.  *
  387.  *    Closes and deallocates a Display structure created with the
  388.  *    TkpOpenDisplay function.
  389.  *
  390.  * Results:
  391.  *    None.
  392.  *
  393.  * Side effects:
  394.  *    Frees up memory.
  395.  *
  396.  *----------------------------------------------------------------------
  397.  */
  398.  
  399. void
  400. TkpCloseDisplay(dispPtr)
  401.     TkDisplay *dispPtr;
  402. {
  403.     Display *display = dispPtr->display;
  404.     HWND hwnd;
  405.  
  406.     if (dispPtr != winDisplay) {
  407.         panic("TkpCloseDisplay: tried to call TkpCloseDisplay on another display");
  408.         return;
  409.     }
  410.  
  411.     /*
  412.      * Force the clipboard to be rendered if we are the clipboard owner.
  413.      */
  414.     
  415.     if (dispPtr->clipWindow) {
  416.     hwnd = Tk_GetHWND(Tk_WindowId(dispPtr->clipWindow));
  417.     if (GetClipboardOwner() == hwnd) {
  418.         OpenClipboard(hwnd);
  419.         EmptyClipboard();
  420.         TkWinClipboardRender(dispPtr, CF_TEXT);
  421.         CloseClipboard();
  422.     }
  423.     }
  424.  
  425.     winDisplay = NULL;
  426.  
  427.     if (display->display_name != (char *) NULL) {
  428.         ckfree(display->display_name);
  429.     }
  430.     if (display->screens != (Screen *) NULL) {
  431.         if (display->screens->root_visual != NULL) {
  432.             ckfree((char *) display->screens->root_visual);
  433.         }
  434.         if (display->screens->root != None) {
  435.             ckfree((char *) display->screens->root);
  436.         }
  437.         if (display->screens->cmap != None) {
  438.             XFreeColormap(display, display->screens->cmap);
  439.         }
  440.         ckfree((char *) display->screens);
  441.     }
  442.     ckfree((char *) display);
  443.     ckfree((char *) dispPtr);
  444. }
  445.  
  446. /*
  447.  *----------------------------------------------------------------------
  448.  *
  449.  * XBell --
  450.  *
  451.  *    Generate a beep.
  452.  *
  453.  * Results:
  454.  *    None.
  455.  *
  456.  * Side effects:
  457.  *    Plays a sounds out the system speakers.
  458.  *
  459.  *----------------------------------------------------------------------
  460.  */
  461.  
  462. void
  463. XBell(display, percent)
  464.     Display* display;
  465.     int percent;
  466. {
  467.     MessageBeep(MB_OK);
  468. }
  469.  
  470. /*
  471.  *----------------------------------------------------------------------
  472.  *
  473.  * TkWinChildProc --
  474.  *
  475.  *    Callback from Windows whenever an event occurs on a child
  476.  *    window.
  477.  *
  478.  * Results:
  479.  *    Standard Windows return value.
  480.  *
  481.  * Side effects:
  482.  *    May process events off the Tk event queue.
  483.  *
  484.  *----------------------------------------------------------------------
  485.  */
  486.  
  487. LRESULT CALLBACK
  488. TkWinChildProc(hwnd, message, wParam, lParam)
  489.     HWND hwnd;
  490.     UINT message;
  491.     WPARAM wParam;
  492.     LPARAM lParam;
  493. {
  494.     LRESULT result;
  495.  
  496.     switch (message) {
  497.     case WM_SETCURSOR:
  498.         /*
  499.          * Short circuit the WM_SETCURSOR message since we set
  500.          * the cursor elsewhere.
  501.          */
  502.  
  503.         result = TRUE;
  504.         break;
  505.  
  506.     case WM_CREATE:
  507.     case WM_ERASEBKGND:
  508.     case WM_WINDOWPOSCHANGED:
  509.         result = 0;
  510.         break;
  511.  
  512.     case WM_PAINT:
  513.         GenerateXEvent(hwnd, message, wParam, lParam);
  514.         result = DefWindowProc(hwnd, message, wParam, lParam);
  515.         break;
  516.  
  517.         case TK_CLAIMFOCUS:
  518.     case TK_GEOMETRYREQ:
  519.     case TK_ATTACHWINDOW:
  520.     case TK_DETACHWINDOW:
  521.         result =  TkWinEmbeddedEventProc(hwnd, message, wParam, lParam);
  522.         break;
  523.  
  524.     default:
  525.         if (!Tk_TranslateWinEvent(hwnd, message, wParam, lParam,
  526.             &result)) {
  527.         result = DefWindowProc(hwnd, message, wParam, lParam);
  528.         }
  529.         break;
  530.     }
  531.  
  532.     /*
  533.      * Handle any newly queued events before returning control to Windows.
  534.      */
  535.  
  536.     Tcl_ServiceAll();
  537.     return result;
  538. }
  539.  
  540. /*
  541.  *----------------------------------------------------------------------
  542.  *
  543.  * Tk_TranslateWinEvent --
  544.  *
  545.  *    This function is called by widget window procedures to handle
  546.  *    the translation from Win32 events to Tk events.
  547.  *
  548.  * Results:
  549.  *    Returns 1 if the event was handled, else 0.
  550.  *
  551.  * Side effects:
  552.  *    Depends on the event.
  553.  *
  554.  *----------------------------------------------------------------------
  555.  */
  556.  
  557. int
  558. Tk_TranslateWinEvent(hwnd, message, wParam, lParam, resultPtr)
  559.     HWND hwnd;
  560.     UINT message;
  561.     WPARAM wParam;
  562.     LPARAM lParam;
  563.     LRESULT *resultPtr;
  564. {
  565.     *resultPtr = 0;
  566.     switch (message) {
  567.     case WM_RENDERFORMAT: {
  568.         TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd);
  569.         if (winPtr) {
  570.         TkWinClipboardRender(winPtr->dispPtr, wParam);
  571.         }
  572.         return 1;
  573.     }
  574.  
  575.     case WM_COMMAND:
  576.     case WM_NOTIFY:
  577.     case WM_VSCROLL:
  578.     case WM_HSCROLL: {
  579.         /*
  580.          * Reflect these messages back to the sender so that they
  581.          * can be handled by the window proc for the control.  Note
  582.          * that we need to be careful not to reflect a message that
  583.          * is targeted to this window, or we will loop.
  584.          */
  585.  
  586.         HWND target = (message == WM_NOTIFY)
  587.         ? ((NMHDR*)lParam)->hwndFrom : (HWND) lParam;
  588.         if (target && target != hwnd) {
  589.         *resultPtr = SendMessage(target, message, wParam, lParam);
  590.         return 1;
  591.         }
  592.         break;
  593.     }
  594.  
  595.     case WM_LBUTTONDOWN:
  596.     case WM_LBUTTONDBLCLK:
  597.     case WM_MBUTTONDOWN:
  598.     case WM_MBUTTONDBLCLK:
  599.     case WM_RBUTTONDOWN:
  600.     case WM_RBUTTONDBLCLK:
  601.     case WM_LBUTTONUP:
  602.     case WM_MBUTTONUP:
  603.     case WM_RBUTTONUP:
  604.     case WM_MOUSEMOVE:
  605.         Tk_PointerEvent(hwnd, (short) LOWORD(lParam),
  606.             (short) HIWORD(lParam));
  607.         return 1;
  608.  
  609.     case WM_CLOSE:
  610.     case WM_SETFOCUS:
  611.     case WM_KILLFOCUS:
  612.     case WM_DESTROYCLIPBOARD:
  613.     case WM_CHAR:
  614.     case WM_SYSKEYDOWN:
  615.     case WM_SYSKEYUP:
  616.     case WM_KEYDOWN:
  617.     case WM_KEYUP:
  618.          GenerateXEvent(hwnd, message, wParam, lParam);
  619.         return 1;
  620.     }
  621.     return 0;
  622. }
  623.  
  624. /*
  625.  *----------------------------------------------------------------------
  626.  *
  627.  * GenerateXEvent --
  628.  *
  629.  *    This routine generates an X event from the corresponding
  630.  *     Windows event.
  631.  *
  632.  * Results:
  633.  *    None.
  634.  *
  635.  * Side effects:
  636.  *    Queues one or more X events.
  637.  *
  638.  *----------------------------------------------------------------------
  639.  */
  640.  
  641. static void
  642. GenerateXEvent(hwnd, message, wParam, lParam)
  643.     HWND hwnd;
  644.     UINT message;
  645.     WPARAM wParam;
  646.     LPARAM lParam;
  647. {
  648.     XEvent event;
  649.     TkWindow *winPtr = (TkWindow *)Tk_HWNDToWindow(hwnd);
  650.  
  651.     if (!winPtr || winPtr->window == None) {
  652.     return;
  653.     }
  654.  
  655.     event.xany.serial = winPtr->display->request++;
  656.     event.xany.send_event = False;
  657.     event.xany.display = winPtr->display;
  658.     event.xany.window = winPtr->window;
  659.  
  660.     switch (message) {
  661.     case WM_PAINT: {
  662.         PAINTSTRUCT ps;
  663.  
  664.         event.type = Expose;
  665.         BeginPaint(hwnd, &ps);
  666.         event.xexpose.x = ps.rcPaint.left;
  667.         event.xexpose.y = ps.rcPaint.top;
  668.         event.xexpose.width = ps.rcPaint.right - ps.rcPaint.left;
  669.         event.xexpose.height = ps.rcPaint.bottom - ps.rcPaint.top;
  670.         EndPaint(hwnd, &ps);
  671.         event.xexpose.count = 0;
  672.         break;
  673.     }
  674.  
  675.     case WM_CLOSE:
  676.         event.type = ClientMessage;
  677.         event.xclient.message_type =
  678.         Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS");
  679.         event.xclient.format = 32;
  680.         event.xclient.data.l[0] =
  681.         Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW");
  682.         break;
  683.  
  684.     case WM_SETFOCUS:
  685.     case WM_KILLFOCUS: {
  686.         TkWindow *otherWinPtr = (TkWindow *)Tk_HWNDToWindow((HWND) wParam);
  687.         
  688.         /*
  689.          * Compare toplevel windows to avoid reporting focus
  690.          * changes within the same toplevel.
  691.          */
  692.  
  693.         while (!(winPtr->flags & TK_TOP_LEVEL)) {
  694.         winPtr = winPtr->parentPtr;
  695.         if (winPtr == NULL) {
  696.             return;
  697.         }
  698.         }
  699.         while (otherWinPtr && !(otherWinPtr->flags & TK_TOP_LEVEL)) {
  700.         otherWinPtr = otherWinPtr->parentPtr;
  701.         }
  702.         if (otherWinPtr == winPtr) {
  703.         return;
  704.         }
  705.  
  706.         event.xany.window = winPtr->window;
  707.         event.type = (message == WM_SETFOCUS) ? FocusIn : FocusOut;
  708.         event.xfocus.mode = NotifyNormal;
  709.         event.xfocus.detail = NotifyNonlinear;
  710.         break;
  711.     }
  712.  
  713.     case WM_DESTROYCLIPBOARD:
  714.         event.type = SelectionClear;
  715.         event.xselectionclear.selection =
  716.         Tk_InternAtom((Tk_Window)winPtr, "CLIPBOARD");
  717.         event.xselectionclear.time = TkpGetMS();
  718.         break;
  719.         
  720.     case WM_CHAR:
  721.     case WM_SYSKEYDOWN:
  722.     case WM_SYSKEYUP:
  723.     case WM_KEYDOWN:
  724.     case WM_KEYUP: {
  725.         unsigned int state = GetState(message, wParam, lParam);
  726.         Time time = TkpGetMS();
  727.         POINT clientPoint;
  728.         POINTS rootPoint;    /* Note: POINT and POINTS are different */
  729.         DWORD msgPos;
  730.  
  731.         /*
  732.          * Compute the screen and window coordinates of the event.
  733.          */
  734.         
  735.         msgPos = GetMessagePos();
  736.         rootPoint = MAKEPOINTS(msgPos);
  737.         clientPoint.x = rootPoint.x;
  738.         clientPoint.y = rootPoint.y;
  739.         ScreenToClient(hwnd, &clientPoint);
  740.  
  741.         /*
  742.          * Set up the common event fields.
  743.          */
  744.  
  745.         event.xbutton.root = RootWindow(winPtr->display,
  746.             winPtr->screenNum);
  747.         event.xbutton.subwindow = None;
  748.         event.xbutton.x = clientPoint.x;
  749.         event.xbutton.y = clientPoint.y;
  750.         event.xbutton.x_root = rootPoint.x;
  751.         event.xbutton.y_root = rootPoint.y;
  752.         event.xbutton.state = state;
  753.         event.xbutton.time = time;
  754.         event.xbutton.same_screen = True;
  755.  
  756.         /*
  757.          * Now set up event specific fields.
  758.          */
  759.  
  760.         switch (message) {
  761.         case WM_SYSKEYDOWN:
  762.         case WM_KEYDOWN:
  763.             /*
  764.              * Check for translated characters in the event queue.
  765.              * Setting xany.send_event to -1 indicates to the
  766.              * Windows implementation of XLookupString that this
  767.              * event was generated by windows and that the Windows
  768.              * extension xkey.trans_chars is filled with the
  769.              * characters that came from the TranslateMessage
  770.              * call.  If it is not -1, xkey.keycode is the
  771.              * virtual key being sent programmatically by generic
  772.              * code.
  773.              */
  774.  
  775.             event.type = KeyPress;
  776.             event.xany.send_event = -1;
  777.             event.xkey.keycode = wParam;
  778.             GetTranslatedKey(&event.xkey);
  779.             break;
  780.  
  781.         case WM_SYSKEYUP:
  782.         case WM_KEYUP:
  783.             /*
  784.              * We don't check for translated characters on keyup
  785.              * because Tk won't know what to do with them.  Instead, we
  786.              * wait for the WM_CHAR messages which will follow.
  787.              */
  788.             event.type = KeyRelease;
  789.             event.xkey.keycode = wParam;
  790.             event.xkey.nchars = 0;
  791.             break;
  792.  
  793.         case WM_CHAR:
  794.             /*
  795.              * Synthesize both a KeyPress and a KeyRelease.
  796.              */
  797.  
  798.             event.type = KeyPress;
  799.             event.xany.send_event = -1;
  800.             event.xkey.keycode = 0;
  801.             event.xkey.nchars = 1;
  802.             event.xkey.trans_chars[0] = (char) wParam;
  803.             Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  804.             event.type = KeyRelease;
  805.             break;
  806.         }
  807.         break;
  808.     }
  809.  
  810.     default:
  811.         return;
  812.     }
  813.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  814. }
  815.  
  816. /*
  817.  *----------------------------------------------------------------------
  818.  *
  819.  * GetState --
  820.  *
  821.  *    This function constructs a state mask for the mouse buttons 
  822.  *    and modifier keys as they were before the event occured.
  823.  *
  824.  * Results:
  825.  *    Returns a composite value of all the modifier and button state
  826.  *    flags that were set at the time the event occurred.
  827.  *
  828.  * Side effects:
  829.  *    None.
  830.  *
  831.  *----------------------------------------------------------------------
  832.  */
  833.  
  834. static unsigned int
  835. GetState(message, wParam, lParam)
  836.     UINT message;        /* Win32 message type */
  837.     WPARAM wParam;        /* wParam of message, used if key message */
  838.     LPARAM lParam;        /* lParam of message, used if key message */
  839. {
  840.     int mask;
  841.     int prevState;        /* 1 if key was previously down */
  842.     unsigned int state = TkWinGetModifierState();
  843.  
  844.     /*
  845.      * If the event is a key press or release, we check for modifier
  846.      * keys so we can report the state of the world before the event.
  847.      */
  848.  
  849.     if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN
  850.         || message == WM_SYSKEYUP || message == WM_KEYUP) {
  851.     mask = 0;
  852.     prevState = HIWORD(lParam) & KF_REPEAT;
  853.     switch(wParam) {
  854.         case VK_SHIFT:
  855.         mask = ShiftMask;
  856.         break;
  857.         case VK_CONTROL:
  858.         mask = ControlMask;
  859.         break;
  860.         case VK_MENU:
  861.         mask = Mod2Mask;
  862.         break;
  863.         case VK_CAPITAL:
  864.         if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) {
  865.             mask = LockMask;
  866.             prevState = ((state & mask) ^ prevState) ? 0 : 1;
  867.         }
  868.         break;
  869.         case VK_NUMLOCK:
  870.         if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) {
  871.             mask = Mod1Mask;
  872.             prevState = ((state & mask) ^ prevState) ? 0 : 1;
  873.         }
  874.         break;
  875.         case VK_SCROLL:
  876.         if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) {
  877.             mask = Mod3Mask;
  878.             prevState = ((state & mask) ^ prevState) ? 0 : 1;
  879.         }
  880.         break;
  881.     }
  882.     if (prevState) {
  883.         state |= mask;
  884.     } else {
  885.         state &= ~mask;
  886.     }
  887.     }
  888.     return state;
  889. }
  890.  
  891. /*
  892.  *----------------------------------------------------------------------
  893.  *
  894.  * GetTranslatedKey --
  895.  *
  896.  *    Retrieves WM_CHAR messages that are placed on the system queue
  897.  *    by the TranslateMessage system call and places them in the
  898.  *    given KeyPress event.
  899.  *
  900.  * Results:
  901.  *    Sets the trans_chars and nchars member of the key event.
  902.  *
  903.  * Side effects:
  904.  *    Removes any WM_CHAR messages waiting on the top of the system
  905.  *    event queue.
  906.  *
  907.  *----------------------------------------------------------------------
  908.  */
  909.  
  910. static void
  911. GetTranslatedKey(xkey)
  912.     XKeyEvent *xkey;
  913. {
  914.     MSG msg;
  915.     
  916.     xkey->nchars = 0;
  917.  
  918.     while (xkey->nchars < XMaxTransChars
  919.         && PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
  920.     if (msg.message == WM_CHAR) {
  921.         xkey->trans_chars[xkey->nchars] = (char) msg.wParam;
  922.         xkey->nchars++;
  923.         GetMessage(&msg, NULL, 0, 0);
  924.         if ((msg.message == WM_CHAR) && (msg.lParam & 0x20000000)) {
  925.         xkey->state = 0;
  926.         }
  927.     } else {
  928.         break;
  929.     }
  930.     }
  931. }
  932.  
  933. /*
  934.  *----------------------------------------------------------------------
  935.  *
  936.  * Tk_FreeXId --
  937.  *
  938.  *    This inteface is not needed under Windows.
  939.  *
  940.  * Results:
  941.  *    None.
  942.  *
  943.  * Side effects:
  944.  *    None.
  945.  *
  946.  *----------------------------------------------------------------------
  947.  */
  948.  
  949. void
  950. Tk_FreeXId(display, xid)
  951.     Display *display;
  952.     XID xid;
  953. {
  954. }
  955.  
  956. /*
  957.  *----------------------------------------------------------------------
  958.  *
  959.  * TkWinResendEvent --
  960.  *
  961.  *    This function converts an X event into a Windows event and
  962.  *    invokes the specified windo procedure.
  963.  *
  964.  * Results:
  965.  *    A standard Windows result.
  966.  *
  967.  * Side effects:
  968.  *    Invokes the window procedure
  969.  *
  970.  *----------------------------------------------------------------------
  971.  */
  972.  
  973. LRESULT
  974. TkWinResendEvent(wndproc, hwnd, eventPtr)
  975.     WNDPROC wndproc;
  976.     HWND hwnd;
  977.     XEvent *eventPtr;
  978. {
  979.     UINT msg;
  980.     WPARAM wparam;
  981.     LPARAM lparam;
  982.  
  983.     if (eventPtr->type == ButtonPress) {
  984.     switch (eventPtr->xbutton.button) {
  985.         case Button1:
  986.         msg = WM_LBUTTONDOWN;
  987.         wparam = MK_LBUTTON;
  988.         break;
  989.         case Button2:
  990.         msg = WM_MBUTTONDOWN;
  991.         wparam = MK_MBUTTON;
  992.         break;
  993.         case Button3:
  994.         msg = WM_RBUTTONDOWN;
  995.         wparam = MK_RBUTTON;
  996.         break;
  997.         default:
  998.         return 0;
  999.     }
  1000.     if (eventPtr->xbutton.state & Button1Mask) {
  1001.         wparam |= MK_LBUTTON;
  1002.     }
  1003.     if (eventPtr->xbutton.state & Button2Mask) {
  1004.         wparam |= MK_MBUTTON;
  1005.     }
  1006.     if (eventPtr->xbutton.state & Button3Mask) {
  1007.         wparam |= MK_RBUTTON;
  1008.     }
  1009.     if (eventPtr->xbutton.state & ShiftMask) {
  1010.         wparam |= MK_SHIFT;
  1011.     }
  1012.     if (eventPtr->xbutton.state & ControlMask) {
  1013.         wparam |= MK_CONTROL;
  1014.     }
  1015.     lparam = MAKELPARAM((short) eventPtr->xbutton.x,
  1016.         (short) eventPtr->xbutton.y);
  1017.     } else {
  1018.     return 0;
  1019.     }
  1020.     return CallWindowProc(wndproc, hwnd, msg, wparam, lparam);
  1021. }
  1022.  
  1023. /*
  1024.  *----------------------------------------------------------------------
  1025.  *
  1026.  * TkpGetMS --
  1027.  *
  1028.  *    Return a relative time in milliseconds.  It doesn't matter
  1029.  *    when the epoch was.
  1030.  *
  1031.  * Results:
  1032.  *    Number of milliseconds.
  1033.  *
  1034.  * Side effects:
  1035.  *    None.
  1036.  *
  1037.  *----------------------------------------------------------------------
  1038.  */
  1039.  
  1040. unsigned long
  1041. TkpGetMS()
  1042. {
  1043.     return GetCurrentTime();
  1044. }
  1045.